package com.sea.base.ext.obs

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.sea.base.ext.global.postMainSmart
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
 * 子线程post，主线程直接set
 * 不需要inline，不然会生成过多的内部类（外部没有内部类，方法额外增加了内部类的都不要inline）
 */
fun <T> MutableLiveData<T>.smartPost(t: T) {
    postMainSmart { value = t }
}

/**
 * 如果重复将不会再发送
 */
fun <T> MutableLiveData<T>.smartPostNoRepeat(t: T) {
    postMainSmart {
        if (t != value) {
            value = t
        }
    }
}

/**
 * 根据参数创建一个obs
 * @param obsOnce 是否只订阅一次
 * @param obsNext 是否忽略当前缓存的值，从下一个消息开始（类似EventBus）
 */
inline fun <T> LiveData<T>.createObserve(
    obsOnce: Boolean = false,
    obsNext: Boolean = false,
    crossinline obs: Observer<T>. (T) -> Unit
) = if (obsNext) {
    observerNexObj {
        this.obs(it)
        if (obsOnce) {
            removeObserver(this)
        }
    }
} else {
    observerObj {
        this.obs(it)
        if (obsOnce) {
            removeObserver(this)
        }
    }
}

/**
 * 由于组合越来越多，这里加个自定义配置
 * @param owner 订阅者的生命周期，如果传null，则需要手动取消
 * @param obsOnce 是否只订阅一次
 * @param obsNext 是否忽略当前缓存的值，从下一个消息开始
 * @param obsRealTime 是否实时获取（[owner]不为null才有用，LiveData默认是活跃状态才会回调，如果为false只要不是Destroy都会收到回调）
 * @return 返回值，用于手动取消订阅
 */
inline fun <T> LiveData<T>.observeCustom(
    owner: LifecycleOwner? = null,
    obsOnce: Boolean = false,
    obsNext: Boolean = false,
    obsRealTime: Boolean = false,
    crossinline obs: Observer<T>. (T) -> Unit
): Observer<T> {
    val o = createObserve(obsOnce, obsNext, obs)

    if (owner == null) {
        observeForever(o)
    } else {
        if (obsRealTime) {
            owner.lifecycle.doOnDestroyed {
                removeObserver(o)
            }
            observeForever(o)
        } else {
            observe(owner, o)
        }
    }
    return o
}

/**
 * 只订阅获取一次
 * @return 方便主动取消
 */
inline fun <T> LiveData<T>.observeOnce(owner: LifecycleOwner, crossinline obs: Observer<T>.(T) -> Unit) =
    observeCustom(owner, obsOnce = true, obs = obs)

/**
 * 订阅无粘性消息，不会收到上一个缓存的data
 */
inline fun <T> LiveData<T>.observerNext(owner: LifecycleOwner, crossinline obs: Observer<T>.(T) -> Unit) =
    observeCustom(owner, obsNext = true, obs = obs)

/**
 * 积攒数据，当再次回来时一次性回调回去
 * 如果有数据时界面已可见，则立即回调该数据
 * @param obsNext false：上一个缓存的data也会收到，true：忽略之前的data，接收下一次及以后的数据
 * @param obs 在此期间收到的所有list数据，按时间正序，list.size>=1
 */
fun <T> LiveData<T>.observerAllWhenActive(
    owner: LifecycleOwner,
    obsNext: Boolean = false,
    obs: Observer<T>.(List<T>) -> Unit
) {
    innerObserverAllWhenActive(owner, obsNext, obs) { _, _ -> }
}

/**
 * 支持自行取消
 * @return 返回函数，用来解绑时调用
 */
fun <T> LiveData<T>.observerAllWhenActiveCanCancel(
    owner: LifecycleOwner,
    obsNext: Boolean = false,
    obs: Observer<T>.(List<T>) -> Unit
): () -> Unit {
    innerObserverAllWhenActive(owner, obsNext, obs) { o, eventObs ->
        return {
            owner.lifecycle.removeObserver(eventObs)
            this.removeObserver(o)
        }
    }
}

@OptIn(ExperimentalContracts::class)
private inline fun <T> LiveData<T>.innerObserverAllWhenActive(
    owner: LifecycleOwner,
    obsNext: Boolean = false,
    crossinline obs: Observer<T>.(List<T>) -> Unit,
    endCall: (o: Observer<T>, eventObs: LifecycleEventObserver) -> Unit,
) {
    contract {
        callsInPlace(endCall, InvocationKind.EXACTLY_ONCE)
    }

    val obsList = arrayListOf<T>()

    val o = createObserve(false, obsNext) {
        obsList.add(it)
        //检查是否可见
        if (owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            //回调数据
            obs(obsList)
            obsList.clear()
        }
    }
    observeForever(o)

    //监听可见状态
    val eventObs = owner.lifecycle.addObserver { owner1, event ->
        when (event) {
            Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME -> {
                if (obsList.isNotEmpty()) {
                    //回调数据
                    o.obs(obsList)
                    obsList.clear()
                }
            }

            Lifecycle.Event.ON_DESTROY -> {
                owner1.lifecycle.removeObserver(this)
            }

            Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP, Lifecycle.Event.ON_ANY -> {
            }
        }
    }

    endCall.invoke(o, eventObs)
}